package org.acghub.demo.campcross;

import java.util.*;

@SuppressWarnings("ClassEscapesDefinedScope")
public class CampCrossMatcher {

    static class CampCrossMatchResult {
        List<CampCrossMatchServerInfo> serverInfos = Collections.emptyList();
        List<List<Integer>> groups = new ArrayList<>();
        int noMatchZoneId;
    }

    static class CampCrossMatchServerInfo implements Comparable<CampCrossMatchServerInfo> {
        // 赛季
        int season;
        // 赛区
        int region;
        // 轮次
        int round;
        // 服务器id
        int zoneId;
        // 服务器分数
        int score;
        // 服务器战力
        long fightPower;

        public int getScore() {
            return score;
        }

        @Override
        public int compareTo(CampCrossMatchServerInfo o) {
            if (score != o.score) {
                return Integer.compare(score, o.score);
            }
            if (fightPower != o.fightPower) {
                return Long.compare(fightPower, o.fightPower);
            }
            return Integer.compare(zoneId, o.zoneId);
        }
        @Override
        public String toString() {
            return "CampCrossMatchServerInfo{" +
                    "season=" + season +
                    ", region=" + region +
                    ", round=" + round +
                    ", zoneId=" + zoneId +
                    ", score=" + score +
                    ", fightPower=" + fightPower +
                    '}';
        }
    }

    public static CampCrossMatchResult match(final List<CampCrossMatchServerInfo> serverInfos, final Set<Integer> blackZoneIds) {
        final CampCrossMatchResult result = new CampCrossMatchResult();
        if (serverInfos == null || serverInfos.isEmpty()) {
            return result;
        }
        final NavigableMap<Integer, List<CampCrossMatchServerInfo>> score2ServerInfos = new TreeMap<>();
        final Set<Integer> zoneIds = new HashSet<>();
        serverInfos.forEach(serverInfo -> {
            score2ServerInfos.computeIfAbsent(serverInfo.score, k -> new ArrayList<>()).add(serverInfo);
            zoneIds.add(serverInfo.zoneId);
        });

        final List<List<CampCrossMatchServerInfo>> poolServerInfos = new ArrayList<>();
        for (List<CampCrossMatchServerInfo> groupServerInfos : score2ServerInfos.values()) {
            Collections.sort(groupServerInfos);
            poolServerInfos.add(groupServerInfos);
        }
        // 奇数, 移除本轮轮空的服务器
        final int size = serverInfos.size();
        final boolean isOdd = size % 2 == 1;
        int moMatchZoneId = 0;
        if (isOdd) {
            // 全部都进过黑名单, 则清空黑名单，重新开始
            final Set<Integer> matchBlackZoneIds = new HashSet<>(blackZoneIds == null ? Collections.emptySet() : new HashSet<>(blackZoneIds));
            if (matchBlackZoneIds.containsAll(zoneIds)) {
                matchBlackZoneIds.clear();
            }
            label:
            for (int i = poolServerInfos.size() - 1; i >= 0; i--) {
                List<CampCrossMatchServerInfo> groupServerInfos = poolServerInfos.get(i);
                for (int j = groupServerInfos.size() - 1; j >= 0; j--) {
                    CampCrossMatchServerInfo serverInfo = groupServerInfos.get(j);
                    if (!matchBlackZoneIds.contains(serverInfo.zoneId)) {
                        groupServerInfos.remove(j);
                        if (groupServerInfos.isEmpty()) {
                            poolServerInfos.remove(i);
                        }
                        moMatchZoneId = serverInfo.zoneId;
                        break label;
                    }
                }
            }
        }
        // 开始匹配
        for (int i = 0; i < poolServerInfos.size(); i++) {
            final List<CampCrossMatchServerInfo> groupServerInfos = poolServerInfos.get(i);
            if (groupServerInfos.isEmpty()) {
                continue;
            }
            // 补位
            if (groupServerInfos.size() % 2 == 1 && i + 1 < poolServerInfos.size()) {
                final List<CampCrossMatchServerInfo> nextGroupServerInfos = poolServerInfos.get(i + 1);
                if (!nextGroupServerInfos.isEmpty()) {
                    groupServerInfos.add(nextGroupServerInfos.remove(0));
                }
            }
            // 每一组匹配配对
            for (int start = 0, end = groupServerInfos.size() - 1; start < end; start++, end--) {
                final CampCrossMatchServerInfo startServerInfo = groupServerInfos.get(start);
                final CampCrossMatchServerInfo endServerInfo = groupServerInfos.get(end);
                result.groups.add(Arrays.asList(startServerInfo.zoneId, endServerInfo.zoneId));
            }
        }
        result.serverInfos = serverInfos;
        result.noMatchZoneId = moMatchZoneId;
        return result;
    }

    public static void main(String[] args) {
        final List<CampCrossMatchServerInfo> serverInfos = new ArrayList<>();
        for (int i = 1; i <= 11; i++) {
            final CampCrossMatchServerInfo serverInfo = new CampCrossMatchServerInfo();
            serverInfo.zoneId = i;
            serverInfo.score = 100 + (i % 3) * 10;
            serverInfo.fightPower = 1000 + i * 100;
            serverInfos.add(serverInfo);
        }
        final Set<Integer> blackZoneIds = new HashSet<>(Arrays.asList(2, 5, 8, 11));
        final CampCrossMatchResult result = match(serverInfos, blackZoneIds);
        System.out.println("no match zoneId: " + result.noMatchZoneId);
        System.out.println("match groups: ");
        for (List<Integer> group : result.groups) {
            System.out.println(group);
        }

    }
}
